const process = require('process')
const Seneca = require('seneca')
const Web = require('seneca-web')
const Express = require('Express')
const _ = require('lodash')
const jsonic = require('jsonic')
const logger = require('./logger')

/**
 * 创建Seneca对象
 * @author tqboss
 * @version 1.0.0
 * @module framework/generator
 * @param {服务名称} serviceName
 * @param {redis配置} redisConfig
 * @param {插件} plugins
 * @returns {seneca对象}
 */
exports.createSeneca = function (appConfig, plugins, pins) {
  const seneca = Seneca({
    tag: appConfig.serviceName,
    log: 'silent',
    timeout: 3000,
    debug: {
      undead: true,
      deprecation: true
    },
    strict: {
      result: true
    },
    transport: {
      redis: {
        url: `redis://${appConfig.redis.host || '127.0.0.1'}:${
          appConfig.redis.port || '6379'
        }?db=${appConfig.redis.db || '0'}${
          appConfig.redis.password
            ? '&password=' + appConfig.redis.password
            : ''
        }`,
        pins: pins
      }
    }
  }).use('seneca-redis-transport-fork')

  const services = _.isArray(plugins) ? plugins : [plugins]
  services.forEach((service) => {
    seneca.use(service, appConfig)
  })
  return seneca
}

/**
 * 创建注册中心客户端
 * @author tqboss
 * @version 1.0.0
 * @module framework/generator
 * @param {配置pattern} pin
 * @param {redis配置} redisConfig
 * @param {回调} callback
 * @returns 远程配置信息
 * @version 1.0.0
 */
exports.createRegistryClient = function (pin, redisConfig, callback) {
  const act = jsonic(pin)
  const seneca = Seneca({
    log: 'silent',
    timeout: 3000,
    debug: {
      undead: true,
      deprecation: true
    },
    transport: {
      redis: {
        url: `redis://${redisConfig.host || '127.0.0.1'}:${
          redisConfig.port || '6379'
        }?db=${redisConfig.db || '0'}${
          redisConfig.password ? '&password=' + redisConfig.password : ''
        }`,
        pins: [`service:${act.service}`]
      }
    }
  })
    .use('seneca-redis-transport-fork')
    .client({ type: 'redis' })
    .act(`${pin},timeout$:3000'`, (err, result) => {
      if (err) {
        logger.error(err.msg)
        process.exit()
      } else if (callback) {
        callback(result)
      } else {
        process.exit()
      }
    })
}

/**
 * 创建注册中心
 * @author tqboss
 * @version 1.0.0
 * @module framework/generator
 * @param {seneca插件} plugins
 * @param {服务配置} appConfig
 * @param {回调} callback
 * @returns {成功后回调}
 */
exports.createRegistry = function (plugins, appConfig, callback) {
  const seneca = this.createSeneca(
    appConfig,
    plugins,
    `service:${appConfig.serviceName}`
  )
  seneca
    .listen({
      type: 'redis'
    })
    .ready(() => {
      if (callback) {
        callback(seneca)
      }
    })
}

/**
 * 创建网关服务
 * @author tqboss
 * @version 1.0.0
 * @module framework/generator
 * @param {注册中心} pin
 * @param {seneca插件} plugins
 * @param {服务配置} appConfig
 * @param {web、act映射回调} callRouter
 * @param {回调:参数为seneca实例} callback
 */
exports.createWebServer = function (
  pin,
  plugins,
  redisConfig,
  callRouter,
  callback
) {
  this.createRegistryClient(pin, redisConfig, (remoteConfig) => {
    const routes = callRouter(remoteConfig.config)
    const seneca = this.createSeneca(
      _.merge(remoteConfig.config, { redis: redisConfig }),
      plugins,
      remoteConfig.services.map((service) => {
        return `service:${service}`
      })
    )
    seneca
      .use(Web, {
        context: Express(),
        routes: routes,
        adapter: require('seneca-web-adapter-express'),
        options: {
          parseBody: false
        }
      })
      .client({ type: 'redis' })
      .ready(() => {
        if (callback) {
          callback(seneca, remoteConfig.config)
        } else {
          process.exit()
        }
      })
  })
}

/**
 * 创建微服务
 * @author tqboss
 * @version 1.0.0
 * @module framework/generator
 * @param {注册中心} pin
 * @param {seneca插件} plugins
 * @param {服务配置} appConfig
 * @param {回调:参数为seneca实例} callback
 */
exports.createMicroservice = function (pin, plugins, redisConfig, callback) {
  this.createRegistryClient(pin, redisConfig, (remoteConfig) => {
    const seneca = this.createSeneca(
      _.merge(remoteConfig.config, { redis: redisConfig }),
      plugins,
      remoteConfig.services.map((service) => {
        return `service:${service}`
      })
    )
    seneca
      .client({ type: 'redis' })
      .listen({ type: 'redis' })
      .ready(() => {
        if (callback) {
          callback(seneca, remoteConfig.config)
        } else {
          process.exit()
        }
      })
  })
}
